﻿/*
 * Time.h
 *
 */
#ifndef __GDK_TIME_H__
#define __GDK_TIME_H__

#include <gdk/core/Types.h>
#include <gdk/core/String.h>
#include <gdk/core/Exception.h>
#include <gdk/core/Property.h>
#include <gdk/core/stdlib.h>
#include <time.h>

#if defined(_WIN32)
#	include <Mmsystem.h>
#	pragma comment(lib,"Winmm.lib")
#else
#	include <sys/time.h>
#endif



namespace gdk
{


// 格林尼治时间转换(Greenwich time)
__INLINE__ int64_t gtime(int64_t timer)
{
	// 格林尼治时间(Greenwich time) 1970-1-1 0:0:0
	return timer + ((1970LL * 365 + 1969 / 4 - 1969 / 100 + 1969 / 400) * (24 * 60 * 60));
}

GDK_CORE_EXPORT int64_t time(int64_t* timer);
GDK_CORE_EXPORT int getTimeBias(void);
GDK_CORE_EXPORT int getZoneBias(const Char *name);
GDK_CORE_EXPORT String getZoneName(int bias);
GDK_CORE_EXPORT int64_t mktime(const struct tm &t);
GDK_CORE_EXPORT struct tm gmtime(const int64_t &timer);
GDK_CORE_EXPORT struct tm localtime(const int64_t &timer);



#ifdef _WIN32

int WINAPI initTimeTick(void);

GDK_CORE_EXPORT uint32_t WINAPI getTimeTick(void);
__INLINE__ uint32_t diffTimeTick(uint32_t begin, uint32_t end)
{
	return (end - begin);
}

#else

__INLINE__ uint32_t getTimeTick(void)
{
	//tv_sec是秒
	//tv_usec是微秒(10E-6 second)
	struct timeval tv;
	::gettimeofday(&tv, NULL);
	return tv.tv_sec * 1000 + (tv.tv_usec / 1000);
}
__INLINE__ uint32_t diffTimeTick(uint32_t begin, uint32_t end)
{
	return (end - begin);
}

#endif


class TimeSpan
{
private:
	int64_t	_timeSpan;


public:
	__INLINE__ TimeSpan(int64_t timeSpan = 0)
		: _timeSpan(timeSpan)
	{}
	__INLINE__ TimeSpan(int64_t days, int64_t hours, int64_t minutes, int64_t seconds)
		: _timeSpan(days * (60 * 60 * 24) + hours * (60 * 60) + minutes * (60) + seconds)
	{}
	__INLINE__ TimeSpan(const TimeSpan &timeSpan)
		: _timeSpan(timeSpan._timeSpan)
	{}

	__INLINE__ int64_t getDays(void) const    { return (_timeSpan / (60 * 60 * 24)); }
	__INLINE__ int64_t getHours(void) const   { return (_timeSpan % (60 * 60 * 24)) / (60 * 60); }
	__INLINE__ int64_t getMinutes(void) const { return (_timeSpan % (60 * 60 * 24) % (60 * 60)) / (60); }
	__INLINE__ int64_t getSeconds(void) const { return (_timeSpan % (60 * 60 * 24) % (60 * 60) % (60)); }

	__INLINE__ int64_t getTotalDays(void) const    { return (_timeSpan / (60 * 60 * 24)); }
	__INLINE__ int64_t getTotalHours(void) const   { return (_timeSpan / (60 * 60)); }
	__INLINE__ int64_t getTotalMinutes(void) const { return (_timeSpan / (60)); }
	__INLINE__ int64_t getTotalSeconds(void) const { return (_timeSpan); }

	__INLINE__ TimeSpan  operator+ (const TimeSpan &span) const { return TimeSpan(_timeSpan + span._timeSpan); }
	__INLINE__ TimeSpan  operator- (const TimeSpan &span) const { return TimeSpan(_timeSpan - span._timeSpan); }
	__INLINE__ TimeSpan& operator+=(const TimeSpan &span)       { _timeSpan += span._timeSpan; return *this; }
	__INLINE__ TimeSpan& operator-=(const TimeSpan &span)       { _timeSpan -= span._timeSpan; return *this; }

	__INLINE__ bool operator==(const TimeSpan &span) const { return _timeSpan == span._timeSpan; }
	__INLINE__ bool operator!=(const TimeSpan &span) const { return _timeSpan != span._timeSpan; }
	__INLINE__ bool operator< (const TimeSpan &span) const { return _timeSpan <  span._timeSpan; }
	__INLINE__ bool operator> (const TimeSpan &span) const { return _timeSpan >  span._timeSpan; }
	__INLINE__ bool operator<=(const TimeSpan &span) const { return _timeSpan <= span._timeSpan; }
	__INLINE__ bool operator>=(const TimeSpan &span) const { return _timeSpan >= span._timeSpan; }

public:
	template<typename TyIs> friend TyIs& operator >>(TyIs &is, TimeSpan &i) __THROW1;
	template<typename TyOs> friend TyOs& operator <<(TyOs &os, const TimeSpan &i) __THROW1;
};


template<typename TyIs>
__INLINE__ TyIs& operator >>(TyIs &is, TimeSpan &i) __THROW1
{
	Varint64 v;
	is >> v;
	i._timeSpan = v;
	return is;
}
template<typename TyOs>
__INLINE__ TyOs& operator <<(TyOs &os, const TimeSpan &i) __THROW1
{
	Varint64 v;
	os << i._timeSpan;
	return os;
}

__INLINE__ void convertPropertyToClass(const JsonValue &json, TimeSpan &timeSpan) __THROW1
{
	timeSpan = TimeSpan(int64_t(json));
}
__INLINE__ void convertPropertyToJson(const TimeSpan &timeSpan, JsonValue &json) __THROW1
{
	json = timeSpan.getTotalSeconds();
}



class Time
{
private:
	int64_t				_time;
	bool mutable		_initLocalTime;
	struct tm mutable	_localTime;


private:
	__INLINE__ void init(int64_t t)
	{
		_time = t;
		_initLocalTime = false;
	}

public:
	__INLINE__ static bool isLeapYear(int year)
	{
		if ( ( ((year % 100 != 0) && (year % 4 == 0))
			|| ((year % 400 == 0))
			)
		&& year != 0
		)
			return true;

		return false;
	}

public:
	__INLINE__ static Time getCurrentTime(void)
	{
		Time t;
		t.init(time(NULL));
		return t;
	}

public:
	__INLINE__ Time(void) { init(getTimeBias()); }
	__INLINE__ Time(const Time &t) { init(t._time); }
	__INLINE__ explicit Time(const Char *text) { if (!convertFromString(text)) { init(getTimeBias()); } }

	__INLINE__ int getYear(void) const { return getLocalTime().tm_year; }
	__INLINE__ int getMonth(void) const { return getLocalTime().tm_mon; }
	__INLINE__ int getDay(void) const { return getLocalTime().tm_mday; }
	__INLINE__ int getHour(void) const { return getLocalTime().tm_hour; }
	__INLINE__ int getMinute(void) const { return getLocalTime().tm_min; }
	__INLINE__ int getSecond(void) const { return getLocalTime().tm_sec; }
	__INLINE__ int getWeekDay(void) const { return getLocalTime().tm_wday; }

	__INLINE__ bool isLeapYear(void) const { return isLeapYear(getYear()); }

	__INLINE__ bool operator < (Time const &t) const { return _time <  t._time; }
	__INLINE__ bool operator <=(Time const &t) const { return _time <= t._time; }
	__INLINE__ bool operator > (Time const &t) const { return _time >  t._time; }
	__INLINE__ bool operator >=(Time const &t) const { return _time >= t._time; }
	__INLINE__ bool operator ==(Time const &t) const { return _time == t._time; }
	__INLINE__ bool operator !=(Time const &t) const { return _time != t._time; }

	__INLINE__ TimeSpan operator - (Time const &t)        const { return TimeSpan(_time - t._time); }
	__INLINE__ Time     operator - (TimeSpan const &span) const { Time t; t.init(_time - span.getTotalSeconds()); return t; }
	__INLINE__ Time     operator + (TimeSpan const &span) const { Time t; t.init(_time + span.getTotalSeconds()); return t; }
	__INLINE__ Time&    operator -=(TimeSpan const &span)       { init(_time - span.getTotalSeconds()); return *this; }
	__INLINE__ Time&    operator +=(TimeSpan const &span)       { init(_time + span.getTotalSeconds()); return *this; }

	__INLINE__ operator int64_t(void) const { return _time; }

	__INLINE__ Time& operator =(const int64_t &t) { init(t); return *this; }
	__INLINE__ Time& operator =(const Time &t) { init(t._time); return *this; }

	GDK_CORE_EXPORT const struct tm& getLocalTime(void) const;
	GDK_CORE_EXPORT String convertToString(bool timezone = true) const;
	GDK_CORE_EXPORT bool convertFromString(const Char *text);

public:
	template<typename TyIs> friend TyIs& operator >>(TyIs &is, Time &i) __THROW1;
	template<typename TyOs> friend TyOs& operator <<(TyOs &os, const Time &i) __THROW1;
};


template<typename TyIs>
__INLINE__ TyIs& operator >>(TyIs &is, Time &o) __THROW1
{
	int64_t t;
	is >> t;
	o.init(t);
	return is;
}
template<typename TyOs>
__INLINE__ TyOs& operator <<(TyOs &os, const Time &o) __THROW1
{
	return os << o._time;
}

//----------------------------------------------------------------------
__INLINE__ void convertPropertyToClass(const JsonValue &json, Time &time) __THROW1
{
	if (!json.isString() || !time.convertFromString(json.asString()))
	{
		__THROW__(__TEXT__("void convertPropertyToClass(JsonValue const &,Time &)"));
	}
}
__INLINE__ void convertPropertyToJson(const Time &time, JsonValue &json) __THROW1
{
	json = time.convertToString();
}




}//namespace gdk


#endif /*__GDK_TIME_H__*/
